package com.baizw.cultivation.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 构建树形菜单
 * MenuUtils
 *
 * @author lishang
 * 2018年8月30日
 */
@Slf4j
public class TreeUtil {

    private static final String ID_FIELD = "id";
    private static final String PARENT_ID_FIELD = "parentId";
    private static final String PARENT_ID_FIELD_ABRIDGE = "pId";
    private static final String CHILDREN_FIELD = "children";
    private static final String SORT_FIELD = "sort";

    /**
     * 构建树形菜单
     *
     * @param sourceList 源数据
     * @param <T>        参数实体
     * @return 组建好的菜单集合
     */
    public static <T> List<T> list2TreeList(Collection<T> sourceList) {
        if(CollUtil.isEmpty(sourceList)){
            return (List<T>) sourceList;
        }
        Object o = ((ArrayList) sourceList).get(0);
        String fieldName = PARENT_ID_FIELD;
        Field field1 = ReflectUtil.getField(o.getClass(), PARENT_ID_FIELD_ABRIDGE);
        if (ObjectUtil.isNotNull(field1)) {
            fieldName = PARENT_ID_FIELD_ABRIDGE;
        }
        return list2TreeList(sourceList, ID_FIELD, fieldName, CHILDREN_FIELD, SORT_FIELD);
    }

    /**
     * 构建树形菜单
     *
     * @param sourceList        源数据
     * @param idFieldName       ID字段名称
     * @param parentIdFieldName 父级ID字段名称
     * @param childrenFieldName 子集字段名称
     * @param sortFieldName     排序字段
     * @param <T>               参数实体
     * @return 组建好的菜单集合
     */
    public static <T> List<T> list2TreeList(Collection<T> sourceList, String idFieldName,
                                            String parentIdFieldName, String childrenFieldName,
                                            String sortFieldName) {
        List<T> targetList = new ArrayList<>();
        if (sourceList == null) {
            return null;
        }
        try {
            List<T> rootList = sourceList.parallelStream()
                    .filter(x -> getFieldValue(x, parentIdFieldName, Long.class).equals(0L) || x == null)
                    .sorted((o1, o2) -> {
                        Integer fieldValue = getFieldValue(o1, sortFieldName, Integer.class);
                        Integer fieldValue1 = getFieldValue(o2, sortFieldName, Integer.class);
                        if (ObjectUtil.isNotNull(fieldValue) && ObjectUtil.isNotNull(fieldValue1)) {
                            return fieldValue > fieldValue1 ? 1 : -1;
                        }
                        return 0;
                    })
                    .collect(Collectors.toList());

            sourceList.removeAll(rootList);
            targetList.addAll(rootList);

            // 递归构建树形
            packTree(rootList, sourceList, idFieldName, parentIdFieldName, childrenFieldName, sortFieldName);
        } catch (Exception e) {
            log.error("树形菜单构建异常", e);
        }
        return targetList;
    }

    /**
     * 封装树（向下递归）
     *
     * @param parentNodeList    要封装为树的父节点对象集合
     * @param originalList      原始list数据
     * @param idFieldName       作为唯一标示的字段名称
     * @param pidFieldName      父节点标识字段名
     * @param childrenFieldName 子节点（列表）标识字段名
     */
    private static <T> void packTree(Collection<T> parentNodeList, Collection<T> originalList, String idFieldName,
                                     String pidFieldName, String childrenFieldName, String sortFieldName) throws Exception {
        for (T parentNode : parentNodeList) {
            // 找到当前父节点的子节点列表
            Long parentId = getFieldValue(parentNode, idFieldName, Long.class);
            List<T> children = originalList.parallelStream()
                    .filter(x -> parentId.equals(getFieldValue(x, pidFieldName, Long.class)))
                    .sorted((x1, x2) -> {
                        Integer fieldValue = getFieldValue(x1, sortFieldName, Integer.class);
                        Integer fieldValue1 = getFieldValue(x2, sortFieldName, Integer.class);
                        if (ObjectUtil.isNotNull(fieldValue) && ObjectUtil.isNotNull(fieldValue1)) {
                            return fieldValue > fieldValue1 ? 1 : -1;
                        }
                        return 0;
                    })
                    .collect(Collectors.toList());
            if (children.isEmpty()) {
                continue;
            }
            ReflectUtil.setFieldValue(parentNode, childrenFieldName, children);
            // 将当前父节点的子节点从原始list移除，减少下次处理数据
            originalList.removeAll(children);

            // 开始下次递归
            packTree(children, originalList, idFieldName, pidFieldName, childrenFieldName, sortFieldName);
        }
    }

    /**
     * 获取Object属性病转为对应类型
     *
     * @param object
     * @param fieldName
     * @param clazz
     * @param <T>
     * @return
     */
    private static <T> T getFieldValue(Object object, String fieldName, Class<T> clazz) {
        Object fieldValue = ReflectUtil.getFieldValue(object, fieldName);
        try {
            return clazz.cast(fieldValue);
        } catch (Exception exception) {
            log.error("类型转化异常", exception);
            return null;
        }
    }

    @Data
    @Accessors(chain = true)
    public static class Test {
        private Long id;
        private Long parentId;
        private Integer sort;
        private List<Test> children;
    }

    public static void main(String[] args) {
        ArrayList<Test> tests = CollUtil.toList(new Test().setId(1L).setParentId(0L).setSort(1));
        List<Test> tests1 = list2TreeList(tests);
        System.out.println(tests1);
    }
}
